/*
 * @Author: aleimu
 * @Date: 2021-03-24 14:24:02
 * @Description: file content
 */

import ReactDOM from 'react-dom';
import React, { useEffect, useState, useRef, useCallback } from "react";

/* 有 bug 的防抖函数
function debounce(fn, ms) {
    let timer;
    return function (...args) {
        if (timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(() => {
            fn(...args)
            timer = null;
        }, ms);
    }
}
function useDebounce(fn, time) {
    console.log('usedebounce')
    return debounce(fn, time);
}
*/

//对之前的Debounce进行改造
function useDebounce(fn, delay) {
    const { current } = useRef({}); //ref改变时不会改变任何值
    //且 其 .current 属性中保存一个可变值的“盒子”，其中可以保存任何值 我们就可以利用这样一个缓存机制
    // 当然他也有其他缓存机制，例如useCallBack和useMemo，但是我实在想不通，如何把timer提出去，除了使用useRef

    /*
    * 原因：因为在class组件，每次重新渲染的都是render下的jsx模板，
    * hook不一样，他每次都会重新渲染全部的hook，因此会导致闭包每次的失效，
    * 不然为什么官方文档中会去做规定，每次渲染的位置必须都是一致的
    * */
    function f(...args) {
        if (current.timer) {
            clearTimeout(current.timer);
        }
        current.timer = setTimeout(fn.bind(undefined, ...args), delay);
    }

    return f
}
// 或者这样
function useDebounce_1(fn, delay, dep = []) {
    const { current } = useRef({ fn, timer: null });
    useEffect(function () {
        current.fn = fn;
    }, [fn]);

    return useCallback(function f(...args) {
        if (current.timer) {
            clearTimeout(current.timer);
        }
        current.timer = setTimeout(() => {
            current.fn.call(this, ...args);
        }, delay);
    }, dep)
}
// 或者这样
function useThrottle(fn, delay, dep = []) {
    const { current } = useRef({ fn, timer: null });
    useEffect(function () {
        current.fn = fn;
    }, [fn]);

    return useCallback(function f(...args) {
        if (!current.timer) {
            current.timer = setTimeout(() => {
                delete current.timer;
            }, delay);
            current.fn.call(this, ...args);
        }
    }, dep);

}


const Fd = function () {
    const [counter1, setCounter1] = useState(0);
    const [counter2, setCounter2] = useState(0);

    const handleClick = useDebounce(function () {
        console.count('click1') // 注意看这里,打印一次算是点击生效一次.
        setCounter1(counter1 + 1)
        // setCounter1(x => x + 1)
    }, 500)


    // 设置一个自动渲染的组件,来模拟防抖组件在多个组件中的使用情况
    useEffect(function () {
        const t = setInterval(() => {
            setCounter2(x => x + 1)
        }, 500);
        return clearInterval.bind(undefined, t)
    }, [])

    // 每次组件重新渲染，都会执行一遍所有的hooks，这样debounce高阶函数里面的timer就不能起到缓存的作用（每次重渲染都被置空）。timer不可靠，debounce的核心就被破坏了。

    return (<div style={{ padding: 30 }}>
        <button
            onClick={function () {
                handleClick()
            }}
        >click</button>
        <div>{counter1}</div>
        <div>{counter2}</div>
    </div>
    )
}


export default Fd